/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *            Copyright (C) 2018 Institute of Computing Technology, CAS
 *               Author : Han Shukai (email : hanshukai@ict.ac.cn)
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *                  The shell acts as a task running in user mode.
 *       The main function is to make system calls through the user's output.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * */

#include <test.h>
#include <string.h>
#include <os.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdint.h>
#include <os/sched.h>
static char blank[] = {"                    "};
static char plane1[] = {"    ___         _   "};
static char plane2[] = {"| __\\_\\______/_|  "};
static char plane3[] = {"<[___\\_\\_______|  "};
static char plane4[] = {"|  o'o              "};
void my_test(void){
	sys_move_cursor(1,1);
	printf("task%d start\n",sys_getpid());
	struct task_info my_test_task = {(uintptr_t)&printf_task2, USER_PROCESS};
	sys_waitpid(sys_spawn(&my_test_task,0,/*AUTO_CLEANUP_ON_EXIT*/ENTER_ZOMBIE_ON_EXIT));
	sys_move_cursor(1,2);
	printf("task%d end\n",sys_getpid());
	sys_exit();
}
void printf_task1(void)
{
    
    int i;
    int print_location = 5;

    for (i = 0;; i++)
    {
        sys_move_cursor(1, print_location);
        printf("> [TASK] This task is to test scheduler. (%d)", i);//printf inclues a sys_write and will syscall
        //user_do_scheduler();
    }
}

void printf_task2(void)
{
    int i;
    int print_location = 6;

    for (i = 0;i<100; i++)
    {
        sys_move_cursor(1, print_location);
        printf("> [TASK] This task is to test scheduler. (%d)", i);
        //user_do_scheduler();
    }
    sys_exit();
}

void drawing_task2(void)
{
    int i, j = 22;

    while (1)
    {
        for (i = 55; i > 0; i--)
        {
            sys_move_cursor(i, j + 0);
            printf("%s", plane1);

            sys_move_cursor(i, j + 1);
            printf("%s", plane2);

            sys_move_cursor(i, j + 2);
            printf("%s", plane3);

            sys_move_cursor(i, j + 3);
            printf("%s", plane4);
        }
         //user_do_scheduler();////
        sys_move_cursor(1, j + 0);
        printf("%s", blank);

        sys_move_cursor(1, j + 1);
        printf("%s", blank);

        sys_move_cursor(1, j + 2);
        printf("%s", blank);

        sys_move_cursor(1, j + 3);
        printf("%s", blank);
    }
}

struct task_info task_test_waitpid = {
    (uintptr_t)&wait_exit_task, USER_PROCESS};
struct task_info task_test_semaphore = {
    (uintptr_t)&semaphore_add_task1, USER_PROCESS};
struct task_info task_test_condition = {
    (uintptr_t)&test_condition, USER_PROCESS};
struct task_info task_test_barrier = {
    (uintptr_t)&test_barrier, USER_PROCESS};

struct task_info task13 = {(uintptr_t)&SunQuan, USER_PROCESS};
struct task_info task14 = {(uintptr_t)&LiuBei, USER_PROCESS};
struct task_info task15 = {(uintptr_t)&CaoCao, USER_PROCESS};
struct task_info task_test_multicore = {(uintptr_t)&test_multicore, USER_PROCESS};

struct task_info task8 = {(uintptr_t)&printf_task1, USER_PROCESS};
struct task_info task9 = {(uintptr_t)&printf_task2, USER_PROCESS};
struct task_info task10 = {(uintptr_t)&drawing_task2, USER_PROCESS};
struct task_info task11 = {(uintptr_t)&my_test, USER_PROCESS};


static struct task_info *test_tasks[16] = {&task_test_waitpid,
                                           &task_test_semaphore,
                                           &task_test_condition,
                                           &task_test_barrier,
                                           &task13, &task14, &task15,
                                           &task_test_multicore,&task8,&task9,&task10,&task11};
static int num_test_tasks = 8;

#define SHELL_BEGIN 25
char * jump_non_num(char *buff){
  if(*buff){
  while((*buff<'0'||*buff>'9')&&*buff!='\0')
    buff++;
  return buff;
  }
  else
    return buff;
}
char * jump_num(char *buff){
  while(*buff>='0'&&*buff<='9')
    buff++;
  return buff;
}
int get_number(char* buff){
  int temp=0;
  buff=jump_non_num(buff);
  for(;*buff>='0'&&*buff<='9';buff++)
    temp=10*temp+*buff-'0';
  return temp;
}
extern pcb_t * volatile current_running;
void test_shell()
{
    // TODO:
    sys_move_cursor(1, SHELL_BEGIN-15);
    printf("------------------- COMMAND -------------------\n");
    int i,len,id;//i用来标识正在检查的buff对应位，len为字符串长度。
    char buff[20];
    char ch;
    for(len=0;;)
    {
        // TODO: call syscall to read UART port
      printf("> root@UCAS_OS: ");
      for(i=0;;){
        //disable_interrupt();
        ch=sys_get_char();
        //enable_interrupt();
        if(ch=='\r'){
          buff[i]='\0';
          len=i;
          printf("\n");
          break;//读到\n的时候进入命令判断
        }
        if(ch=='\b'&&i>=0){
          buff[--i]='\0';
          sys_move_cursor(current_running->cursor_x-1,current_running->cursor_y);
          printf(" ");
          sys_move_cursor(current_running->cursor_x-1,current_running->cursor_y);
        }
        else{
          buff[i++]=ch;
          printf("%c",ch);
        }
      }
      switch(buff[0]){
        case 'p'://ps
                sys_process_show();
                break;
        case 'c'://clear
                sys_screen_clear();
                break;
        case 'k'://kill
                id=get_number(buff);
                if(!sys_kill(id))
                  prints("error:no such process with id %d",id);;
                break;
        case 'e'://exec
                id=get_number(buff);
                //char *buff_temp=jump_non_num(buff);
                //buff_temp=jump_num(buff_temp);

                //pid_t sys_spawn(task_info_t *info, void* arg, spawn_mode_t mode);
                if(id>=16)
                  printf("no such a process\n");
                else
                printf("exec process[%d]\n",sys_spawn(test_tasks[id],0,AUTO_CLEANUP_ON_EXIT));
                break;
        default:
                printf("illegal command^_+()+_^\n");
      }

        // TODO: parse input
        // note: backspace maybe 8('\b') or 127(delete)

        // TODO: ps, exec, kill, clear
    }
}
